package cn.seqdata.forecast.model.moving;

import cn.seqdata.forecast.model.AbstractModel;
import cn.seqdata.forecast.model.ModelParams;
import org.hawkular.datamining.forecast.DataPoint;
import org.hawkular.datamining.forecast.models.SimpleMovingAverage;
import org.joda.time.DateTime;
import org.joda.time.ReadableInterval;
import org.joda.time.ReadablePeriod;

import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;

import static org.apache.commons.lang3.ArrayUtils.toArray;

/**
 * @Author: shua
 * @Date: 2019/6/18 10:37
 * @Description: 特殊的移动平均算法
 * values按照ModelParams.LENGTH长度分组，并且取每组相同下标的数据算平均
 */
public class SpecialMovingAverageModel extends AbstractModel<ModelParams> {
    private double[] values;

    @Override
    public void learn(double[] values) {
        this.values = values;
    }

    @Override
    public double[] forecast(int n) {
        if (n <= 0) {
            throw new IllegalArgumentException("n <= 0");
        }

        if (Objects.isNull(getParams().getLength()) || getParams().getLength() <= 0) {
            throw new IllegalArgumentException("length is not null or length <= 0");
        }

        double[] weights = new double[values.length / getParams().getLength()];
        Arrays.fill(weights, 1.0 / (values.length / getParams().getLength()));
        double[] result = new double[n];
        Arrays.fill(result, Double.NaN);

        LinkedBlockingQueue<Double> window = new LinkedBlockingQueue<>(weights.length);
        for (int y = 0; y < getParams().getLength() && y < n; y++) {
            for (int x = 0; x + y < values.length; x += getParams().getLength()) {
                window.add(values[x + y]);

                if (window.remainingCapacity() == 0) {
                    Iterator<Double> iterator = window.iterator();
                    int counter = 0;
                    double sum = 0;
                    while (iterator.hasNext()) {
                        double value = iterator.next();
                        sum += value * weights[counter++];
                    }
                    result[y] = sum;

                    window.clear();
                }
            }
        }

        return result;
    }

    @Override
    public AbstractModel<ModelParams> create(ModelParams params) {
        SpecialMovingAverageModel model = new SpecialMovingAverageModel();

        model.setParams(params);

        return model;
    }
}
